package client

import (
	"bytes"
	"fmt"
	"net/http"
	"strings"
	"time"
	"unicode/utf8"
	"yunj/app/service/client/logservice"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
)

// 日志中间件
func Log() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 创建自定义 ResponseRecorder
		recorder := &responseRecorder{
			ResponseWriter: ctx.Writer,
			statusCode:     http.StatusOK, // 默认状态码
		}
		ctx.Writer = recorder // 替换原始 ResponseWriter

		// 执行前记录一次
		logservice.Record(ctx)
		// 执行
		ctx.Next()

		// 执行后记录一次，也可补充完善当前权限和登录成员id
		appendArgs := logservice.AppendArgs{
			EndTime: time.Now().In(time.Local), // 计算耗时
		}

		// statusCode := ctx.Writer.Status()
		// 获取json响应体（需注意：若响应体是流式写入，可能无法完整捕获，此处适用于非流式响应）
		bodyCharCount := recorder.GetBodyCharCount()
		if bodyCharCount > 0 && bodyCharCount < 5000 && recorder.IsJson() {
			body := recorder.GetBody()
			if body != "" {
				jsonContent, err := util.TruncateJson(body, 200)
				if err != nil {
					fmt.Printf("日志中间件：json截取错误：%v\r\n", err)
				} else {
					appendArgs.ResponseContent = jsonContent
				}
			}
		}

		logservice.Record(ctx, appendArgs)
	}
}

// responseRecorder 自定义 ResponseWriter，用于记录响应数据
type responseRecorder struct {
	gin.ResponseWriter               // 嵌入原生 ResponseWriter，继承所有方法
	statusCode         int           // 响应状态码
	bodyBuffer         *bytes.Buffer // 存储响应体
}

// 重写 WriteHeader 方法，记录状态码
func (r *responseRecorder) WriteHeader(statusCode int) {
	r.statusCode = statusCode
	r.ResponseWriter.WriteHeader(statusCode)
}

// 重写 Write 方法，记录响应体并将数据发送给客户端
func (r *responseRecorder) Write(b []byte) (int, error) {
	if r.bodyBuffer == nil {
		r.bodyBuffer = bytes.NewBuffer([]byte{})
	}

	// 先写入缓冲区
	n, err := r.bodyBuffer.Write(b)
	if err != nil {
		return n, err
	}

	// 再将数据写入原始ResponseWriter，这样客户端才能收到响应
	return r.ResponseWriter.Write(b)
}

// IsJSON 判断响应是否为 JSON 格式
func (r *responseRecorder) IsJson() bool {
	contentType := r.Header().Get("Content-Type")
	return strings.Contains(contentType, "application/json")
}

// GetBody 获取响应体
func (r *responseRecorder) GetBody() string {
	if r.bodyBuffer == nil {
		return ""
	}
	return r.bodyBuffer.String()
}

// GetBodyCharCount 获取响应体字符数（Unicode码点）
func (r *responseRecorder) GetBodyCharCount() int {
	if r.bodyBuffer == nil {
		return 0
	}
	return utf8.RuneCountInString(r.bodyBuffer.String())
}
